#ifndef SCD4X_I2C_OPTIMIZED_H
#define SCD4X_I2C_OPTIMIZED_H

#include "main/boards/common/i2c_device.h"
#include <driver/i2c_master.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <cstdint>
#include <cassert>
#include <string>
#include "esp_timer.h"
#include <esp_err.h>

/**
 * @file scd4x_i2c_optimized.h
 * @brief 优化的SCD4X传感器驱动类，包含专用I2C工具函数封装
 * @author 嵌入式系统工程师
 * @version 1.0
 * @date 2024-05-20
 */

class SCD4X : public I2cDevice {
public:
    // 传感器命令定义
    static constexpr uint16_t SCD4X_STOP_PERIODIC_MEASURE = 0x0104;
    static constexpr uint16_t SCD4X_START_PERIODIC_MEASURE = 0x0100;
    static constexpr uint16_t SCD4X_START_LOW_POWER_MEASURE = 0x0106;
    static constexpr uint16_t SCD4X_READ_MEASUREMENT = 0x0300;
    static constexpr uint16_t SCD4X_PERFORM_SELF_TEST = 0x3632;
    static constexpr uint16_t SCD4X_WAKE_UP = 0x3615;
    static constexpr uint16_t SCD4X_POWER_DOWN = 0x36E0;
    static constexpr uint16_t SCD4X_SET_TEMPERATURE_OFFSET = 0x241D;
    static constexpr uint16_t SCD4X_GET_DATA_READY_STATUS = 0xE4B8;
    static constexpr uint16_t SCD4X_MEASURE_SINGLE_SHOT = 0x219D;
    static constexpr uint16_t SCD4X_MEASURE_SINGLE_SHOT_RHT_ONLY = 0x2196;
    static constexpr uint16_t SCD4X_GET_TEMPERATURE_OFFSET = 0x2318;
    static constexpr uint16_t SCD4X_SET_SENSOR_ALTITUDE = 0x2427;
    static constexpr uint16_t SCD4X_GET_SENSOR_ALTITUDE = 0x2322;
    static constexpr uint16_t SCD4X_SET_AMBIENT_PRESSURE = 0xE000;
    static constexpr uint16_t SCD4X_PERFORM_FORCED_RECALIB = 0x362F;
    static constexpr uint16_t SCD4X_SET_AUTOMATIC_CALIB = 0x2416;
    static constexpr uint16_t SCD4X_GET_AUTOMATIC_CALIB = 0x2313;
    static constexpr uint16_t SCD4X_PERSIST_SETTINGS = 0x3615;
    static constexpr uint16_t SCD4X_GET_SERIAL_NUMBER = 0x3682;
    static constexpr uint16_t SCD4X_PERFORM_FACTORY_RESET = 0x3632;
    static constexpr uint16_t SCD4X_REINIT = 0x3646;
    
    // 测量模式枚举
    enum MeasureMode {
        SCD4X_MODE_PERIODIC,
        SCD4X_MODE_LOW_POWER
    };
    
    // 测量数据结构
    struct Measurement {
        uint16_t co2_ppm;      // CO2浓度，单位：ppm
        float temperature;     // 温度，单位：摄氏度
        float humidity;        // 湿度，单位：相对湿度百分比
    };
    
    /**
     * @brief 构造函数
     * @param i2c_bus I2C总线句柄
     * @param addr 传感器I2C地址，默认0x62
     */
    SCD4X(i2c_master_bus_handle_t i2c_bus, uint8_t addr = 0x62);
    
    /**
     * @brief 析构函数
     */
    ~SCD4X();
    
    /**
     * @brief 初始化传感器
     * @return 成功返回true，失败返回false
     */
    bool begin();
    
    /**
     * @brief 读取测量数据
     * @param data 存储测量数据的结构体指针
     * @return 成功返回true，失败返回false
     */
    bool readMeasurement(Measurement* data);
    
    /**
     * @brief 检查数据是否就绪
     * @return 数据就绪返回true，否则返回false
     */
    bool getDataReadyStatus();
    
    /**
     * @brief 设置睡眠模式
     * @param sleep true进入睡眠模式，false唤醒传感器
     */
    void setSleepMode(bool sleep);
    
    /**
     * @brief 启用周期性测量
     * @param mode 测量模式
     * @return 成功返回true，失败返回false
     */
    bool enablePeriodMeasure(MeasureMode mode = SCD4X_MODE_PERIODIC);
    
    /**
     * @brief 执行单次测量
     * @param rht_only 是否仅测量温湿度
     * @return 成功返回true，失败返回false
     */
    bool measureSingleShot(bool rht_only = false);
    
    /**
     * @brief 执行传感器自检
     * @return 自检结果，0表示成功，其他值表示失败
     */
    uint16_t performSelfTest();
    
    /**
     * @brief 设置温度偏移
     * @param temp_offset 温度偏移值，单位：摄氏度
     * @return 成功返回true，失败返回false
     */
    bool setTemperatureOffset(float temp_offset);
    
    /**
     * @brief 获取温度偏移
     * @return 温度偏移值，单位：摄氏度
     */
    float getTemperatureOffset();
    
    /**
     * @brief 设置传感器海拔高度
     * @param altitude 海拔高度，单位：米
     * @return 成功返回true，失败返回false
     */
    bool setSensorAltitude(uint16_t altitude);
    
    /**
     * @brief 获取传感器海拔高度
     * @return 海拔高度，单位：米
     */
    uint16_t getSensorAltitude();
    
    /**
     * @brief 设置环境气压
     * @param pressure 气压，单位：百帕
     * @return 成功返回true，失败返回false
     */
    bool setAmbientPressure(uint32_t pressure);
    
    /**
     * @brief 设置自动校准模式
     * @param enable 是否启用自动校准
     * @return 成功返回true，失败返回false
     */
    bool setAutomaticCalibration(bool enable);
    
    /**
     * @brief 获取自动校准模式状态
     * @return 自动校准模式是否启用
     */
    bool getAutomaticCalibration();
    
    /**
     * @brief 保存设置到传感器EEPROM
     * @return 成功返回true，失败返回false
     */
    bool persistSettings();
    
    /**
     * @brief 获取传感器序列号
     * @param serial 存储序列号的数组（3个16位整数）
     * @return 成功返回true，失败返回false
     */
    bool getSerialNumber(uint16_t serial[3]);
    
    /**
     * @brief 执行强制校准
     * @param co2_ppm 参考CO2浓度，单位：ppm
     * @return 校准值，如果失败则返回-1
     */
    int16_t performForcedRecalibration(uint16_t co2_ppm);
    
    /**
     * @brief 重置传感器
     * @return 成功返回true，失败返回false
     */
    bool reinit();
    
    /**
     * @brief 恢复出厂设置
     * @return 成功返回true，失败返回false
     */
    bool performFactoryReset();
    
private:
    // CRC常量
    static constexpr uint8_t SCD4X_CRC8_INIT = 0xFF;
    static constexpr uint8_t SCD4X_CRC8_POLYNOMIAL = 0x31;
    
    // 日志标签
    static constexpr const char* TAG = "SCD4X";
    
    // 默认超时时间
    static constexpr int DEFAULT_TIMEOUT_MS = 1000;
    
    // 默认重试次数
    static constexpr int DEFAULT_RETRY_COUNT = 3;
    
    // 传感器配置数据
    float temp_comp_ = 0.0f;
    uint16_t sensor_altitude_ = 0;
    
    /**
     * @brief 发送16位命令到传感器
     * @param cmd 16位命令
     * @param timeout_ms 超时时间(毫秒)
     * @param retries 重试次数
     * @return 成功返回ESP_OK，失败返回错误码
     */
    esp_err_t sendCommand(uint16_t cmd, int timeout_ms = DEFAULT_TIMEOUT_MS, int retries = DEFAULT_RETRY_COUNT);
    
    /**
     * @brief 发送带参数的16位命令
     * @param cmd 16位命令
     * @param param 16位参数
     * @param timeout_ms 超时时间(毫秒)
     * @param retries 重试次数
     * @return 成功返回ESP_OK，失败返回错误码
     */
    esp_err_t sendCommandWithParam(uint16_t cmd, uint16_t param, int timeout_ms = DEFAULT_TIMEOUT_MS, int retries = DEFAULT_RETRY_COUNT);
    
    /**
     * @brief 发送命令并接收数据
     * @param cmd 16位命令
     * @param data 接收数据的缓冲区
     * @param data_len 接收数据的长度
     * @param timeout_ms 超时时间(毫秒)
     * @param retries 重试次数
     * @return 成功返回ESP_OK，失败返回错误码
     */
    esp_err_t sendCommandAndRead(uint16_t cmd, uint8_t* data, size_t data_len, int timeout_ms = DEFAULT_TIMEOUT_MS, int retries = DEFAULT_RETRY_COUNT);
    
    /**
     * @brief 计算CRC8校验值
     * @param data 要计算CRC的数据
     * @param len 数据长度
     * @return CRC8校验值
     */
    uint8_t calculateCRC(const uint8_t* data, size_t len);
    
    /**
     * @brief 验证CRC校验
     * @param data 带CRC的数据
     * @param len 数据长度（不包括CRC）
     * @return 校验通过返回true，否则返回false
     */
    bool verifyCRC(const uint8_t* data, size_t len);
    
    /**
     * @brief 将16位整数转换为大端字节序
     * @param value 要转换的值
     * @param bytes 存储转换后字节的缓冲区
     */
    void uint16ToBigEndian(uint16_t value, uint8_t* bytes);
    
    /**
     * @brief 从大端字节序转换为16位整数
     * @param bytes 大端字节序的字节
     * @return 转换后的16位整数
     */
    uint16_t bigEndianToUint16(const uint8_t* bytes);
};

#endif // SCD4X_I2C_OPTIMIZED_H